Agenda

Reminders

  • Midterm is June 9\(^{th}\) in class
    • Review is posted on Canvas
    • Let me know if you have any questions or want solutions to previous assignments
  • Final Project Ideas + Groups due ———-
    • need a “solid” idea of what you might look at
    • need data sets, or ideas for data sets
      • these do not need to be your final data sets, but I just want to see you have been thinking about this project
    • You can work by yourself or with a partner
    • Fill out the canvas “quiz” to let me know if you want to work by yourself or with someone else.
    • If you want to work with a partner, but don’t know who to work with, let me know and I will find someone

PackageName::FunctionName

```r
library(tidyverse)
head(diamonds)


#?filter

#filter from dplyr
diamonds %>%
  dplyr::filter(color == \E\) %>%
  head()

<!-- rnb-source-end -->

<!-- rnb-frame-begin eyJtZXRhZGF0YSI6eyJjbGFzc2VzIjpbInRibF9kZiIsInRibCIsImRhdGEuZnJhbWUiXSwibnJvdyI6NiwibmNvbCI6MTAsInN1bW1hcnkiOnsiQSB0aWJibGUiOiI2IMOXIDEwIn19LCJyZGYiOiJINHNJQUFBQUFBQUFBNTFVUFd6VFFCUSsvOFFtbGtoU3RYTmhaRW1rTkFzTHlnMXQwa0JKVWdwUmh5N1grTkphT0had0hLQmxZZW5jR1ZZa3hzNGRFU09pRERBd2QyR0JsWVdoNFozdm51TjY3RWxQOTczbmU5KzllL2VkbjZ6dk5weGRoeEJpRUZQWGlGRUFTQXJQbnJhcTl3bEV3TkdJU1lwaWZnMkxsZ0dJMVNVd3Eza3grZkRUZWZDaStlV3lmYlp5ZkpuNjMwLzM3djM5Zk5yOEFSNkVtdC9PdDMrZnJKNUQvbTJSSjNZQU04SDB6R3prTnJSOC9wTDdVMENWSkVOR3pSYnpJc1R0TUhRVkxnNTRkSFEzRTdEN0VSOTdzN0Z5Q3gyWE16KzNSV0hvc3ludW9HTmlHTGs4NHNoampkZ3dEaU5BVjVrRDZCa1R2aTFOc090elJXaGo1OVlSYkNCb0lXZ2oyRVRRUWZCUTBobnptOVpuNUJwdDVlcTdwUmowVGwwaFk2ZXp0b0JwZExDenRvQVlOUWVMc01EMWxLMTFnOEtsb21qM2s5QWZvWTkvamNTZ1c5T0dHTFRYVVBOSEdlOGwweWpOZS9SVzVuWFYzS2VLaDF5ZnQrUjNHS3BSY0JQUzJtQmRzQjVZUCtVdHZ4UGpQUzJ2Q2duZm9SVlZSK1dyR0JkMEtSSDZIaTJmSkFzV2VWTDV0Q1NWVHl2SkE5bWtGZUZ0LzZGTHNuNWFGdUgyV1pwbnlCZEVkUkZkZVpQT2hZVE9vWlk2aHlINTgzSU8ySmlqbkoxVTR5eGlNZDdmY0JhbjhkQVA4U1haOEJBaUx6N0NieTZmeElmb3hHemY1K2hNSW0rSUR2d1NGTUJFN1RoWFVqRUtYOVd3TE5GelhkekFmRDcvbHhNSkpqZ3VpMWx0RkVHS1ZNWTFPanVjeEY0WUFKbStySlNlVGRZaUl2OVBtckxzeC9Jc0VJVzQxZUhoTEhoZXJXZVdvaUEweFluWWtkdWJXS1NGMHVYQmdSZGdHMnc0M1pRZHBDM3kyVDczbFZPQzh5ZkhyMEhqQXV5OUE5RnBMUTVqaHVzY3VBMk15QWR4OVI5L3VLam5uQVVBQUE9PSJ9 -->

<div data-pagedtable="false">
  <script data-pagedtable-source type="application/json">
{"columns":[{"label":["carat"],"name":[1],"type":["dbl"],"align":["right"]},{"label":["cut"],"name":[2],"type":["ord"],"align":["right"]},{"label":["color"],"name":[3],"type":["ord"],"align":["right"]},{"label":["clarity"],"name":[4],"type":["ord"],"align":["right"]},{"label":["depth"],"name":[5],"type":["dbl"],"align":["right"]},{"label":["table"],"name":[6],"type":["dbl"],"align":["right"]},{"label":["price"],"name":[7],"type":["int"],"align":["right"]},{"label":["x"],"name":[8],"type":["dbl"],"align":["right"]},{"label":["y"],"name":[9],"type":["dbl"],"align":["right"]},{"label":["z"],"name":[10],"type":["dbl"],"align":["right"]}],"data":[{"1":"0.23","2":"Ideal","3":"E","4":"SI2","5":"61.5","6":"55","7":"326","8":"3.95","9":"3.98","10":"2.43"},{"1":"0.21","2":"Premium","3":"E","4":"SI1","5":"59.8","6":"61","7":"326","8":"3.89","9":"3.84","10":"2.31"},{"1":"0.23","2":"Good","3":"E","4":"VS1","5":"56.9","6":"65","7":"327","8":"4.05","9":"4.07","10":"2.31"},{"1":"0.29","2":"Premium","3":"I","4":"VS2","5":"62.4","6":"58","7":"334","8":"4.20","9":"4.23","10":"2.63"},{"1":"0.31","2":"Good","3":"J","4":"SI2","5":"63.3","6":"58","7":"335","8":"4.34","9":"4.35","10":"2.75"},{"1":"0.24","2":"Very Good","3":"J","4":"VVS2","5":"62.8","6":"57","7":"336","8":"3.94","9":"3.96","10":"2.48"}],"options":{"columns":{"min":{},"max":[10],"total":[10]},"rows":{"min":[10],"max":[10],"total":[6]},"pages":{}}}
  </script>
</div>

<!-- rnb-frame-end -->

<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuTkFcbk5BXG5OQVxuYGBgXG5gYGAifQ== -->

```r
```r
NA
NA
NA

<!-- rnb-source-end -->

<!-- rnb-frame-begin eyJtZXRhZGF0YSI6eyJjbGFzc2VzIjpbInRibF9kZiIsInRibCIsImRhdGEuZnJhbWUiXSwibnJvdyI6NiwibmNvbCI6MTAsInN1bW1hcnkiOnsiQSB0aWJibGUiOiI2IMOXIDEwIn19LCJyZGYiOiJINHNJQUFBQUFBQUFBNTFVTzJ3VFFSRGQrOWpHSjNGMkZCcWFRQmtLVzNMYzBFVGVJdGd4SDJNbllBV0padVBiSkNmT2QyWjlCbUlhbXRUVTBOS25kb25vUU5BaFVhZWhnUllLaXBqWjI1M3pCNnFzTk5vM2N6T3pzN052Ym1kcnIrcnNPWVFRaTlpbVFhd01RSko1K0tCZXVrbkFBb3BCYkpLWCt3dHdXZ1VndlYyUWJPM0w0TjAzWi9OcDdkTlo0L1RLK0N6VlA2Ly8rdkQ2OFkzYXh6ZHl2YTE5SFV1SGx4Qi9XY2JKRTBCc0VIV0F3dmJTZ2RtQVArUEJFRkF4aVZCV3U4NThnYmdSUlo3RytTNFh4OWZuRExtMjRIMS8xTmRxcHVseEZpd2RrZWtGYklnbm1CZ1lDWThMam5teUI2d1hSd0xRK2R3RnpQK0x6RzVPZGNJY2RtNEx3UzBFZFFRTkJOc0ltZ2h1cTNUVzlLTDFXZjgyZXFHK1N6cUQyYXhvWk8wMk4yWXd0WFozTjJZUXJYWjNacGE0a21hclg2Qnd4U2phZWkvNVIraTk3d2R5MGJ2RHFseTBYVmQ2NjJyQ0tOcFM5alR1emlzVjE5SjdteTdxOTRuT1MzRHBSc0ZMS0dtQWRFQWVLZEY1QzRyQnRMQTI2Znc0dVVhTFZWV1BLd20rL3B1NllGMmI3TkNWazhSaEZnZHpBTU5BM1VuaVFJdkpnR3hUZHpNWkVlcnFlbGFrdVhHYXhsbHFncWlwSmliZExabWw4NU9hYXJKb1J2a3QwemxrZlk1MGRsS09NOEZpZkwvZUtFN3RVUkRoSk9WZ0VJUWZIK00zancvaUkxUml0aDl3VkFiQzc2RUN2d1FOTU5BWUw1V1VGOUh6TXBZbGUyN0tGNWxPcDMrV1NJSUJqc2RpVmo0UUVLS1lzWkF1RncxaVB3b2htYm1xbVQ0ZmJBaWkvaytHbHZtUGhWRW9DL0ZLdmFOUitLUlVtWE5GUWhnNkoySkhIVzlqa1Zta0xnOFAvUkRia0lQYkRkbGgycUtBN2ZOQUt5N2NQN2wrR1JvWFl1OGRzQTdMY1JRejlIUGdOZENpQnVMOEwxTXlwNzZjQlFBQSJ9 -->

<div data-pagedtable="false">
  <script data-pagedtable-source type="application/json">
{"columns":[{"label":["carat"],"name":[1],"type":["dbl"],"align":["right"]},{"label":["cut"],"name":[2],"type":["ord"],"align":["right"]},{"label":["color"],"name":[3],"type":["ord"],"align":["right"]},{"label":["clarity"],"name":[4],"type":["ord"],"align":["right"]},{"label":["depth"],"name":[5],"type":["dbl"],"align":["right"]},{"label":["table"],"name":[6],"type":["dbl"],"align":["right"]},{"label":["price"],"name":[7],"type":["int"],"align":["right"]},{"label":["x"],"name":[8],"type":["dbl"],"align":["right"]},{"label":["y"],"name":[9],"type":["dbl"],"align":["right"]},{"label":["z"],"name":[10],"type":["dbl"],"align":["right"]}],"data":[{"1":"0.23","2":"Ideal","3":"E","4":"SI2","5":"61.5","6":"55","7":"326","8":"3.95","9":"3.98","10":"2.43"},{"1":"0.21","2":"Premium","3":"E","4":"SI1","5":"59.8","6":"61","7":"326","8":"3.89","9":"3.84","10":"2.31"},{"1":"0.23","2":"Good","3":"E","4":"VS1","5":"56.9","6":"65","7":"327","8":"4.05","9":"4.07","10":"2.31"},{"1":"0.22","2":"Fair","3":"E","4":"VS2","5":"65.1","6":"61","7":"337","8":"3.87","9":"3.78","10":"2.49"},{"1":"0.20","2":"Premium","3":"E","4":"SI2","5":"60.2","6":"62","7":"345","8":"3.79","9":"3.75","10":"2.27"},{"1":"0.32","2":"Premium","3":"E","4":"I1","5":"60.9","6":"58","7":"345","8":"4.38","9":"4.42","10":"2.68"}],"options":{"columns":{"min":{},"max":[10],"total":[10]},"rows":{"min":[10],"max":[10],"total":[6]},"pages":{}}}
  </script>
</div>

<!-- rnb-frame-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->





## Building Graphics

1. Draw by hand (or imagine) the specific plot that you intend to construct
2. Data Wrangling (if needed) to get the data in glyph-ready form, or verify that the current form is glyph-ready for your purposes.
3. Establish the frame using a `ggplot()` statement
4. Create the intended glyph using `geom_[style]()` such as
    - `geom_point()`
    - `geom_bar()`
    - `geom_boxplot()`
    - `geom_density()`
    - `geom_vline()`
    - `geom_segment()`
    - `geom_histogram()`
    - and *many* more
5. Map variables to the graphical attributes of the glyph using: `aes( )`
  - Rule of thumb: anytime when you are plotting with ggplot, ALL variables need to be inside an `aes` (except facets, later in slides), and all constants go outside of the `aes`.
    - e.g. `geom_point(aes(color = gender))` vs. `geom_point(color = "red")`
  
6. Add additional layers to the frame using the `+` symbol 
    - Note: **not** `%>%` between layers of `ggplot2` graphics
    - Think `+` is equivalent of "add layer on top of ..." in `ggplot2` portions, whereas `%>%` is  "and then the next step is..."

*Steps 4 and 5 can be switched.*

![https://twitter.com/tanya_shapiro/status/1576935152575340544?t=vwaW8h6CC62h0pkwv9n5Yg&s=19](images/ggplot-cake.jpg)


## Example: Baby Names 

Let's look at our `BabyNames` names data set agian. 


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyBpbnNwZWN0IGRhdGEgaW50YWtlXG5nbGltcHNlKEJhYnlOYW1lcylcblxuYGBgIn0= -->

```r
# inspect data intake
glimpse(BabyNames)
Rows: 1,792,091
Columns: 4
$ name  <chr> "Mary", "Anna", "Emma", "Elizabeth", "Minnie", "Margaret", "Ida", "…
$ sex   <chr> "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F…
$ count <int> 7065, 2604, 2003, 1939, 1746, 1578, 1472, 1414, 1320, 1288, 1258, 1…
$ year  <int> 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1…

wrangle into glyph-ready form

in the beginning you might use mplot to get started–here’s the default result

The graph looks perfectly fine, but this code isn’t easy to read.

This is why we stress writing readable code!

we can do better

  1. establish the frame
  2. plot the glyphs (i.e., select a geom)
  3. map the aesthetics
  4. add labels and title
  5. other features (e.g., alpha, sizing, etc)

Our Plot

  1. Establish the Frame

Nothing is here! That is exactly what is supposed to happen. Calling ggplot() only tells us R that we are ready to plot and I want to create some space to make my plot.

ggplot(data = Names) 

NA
  1. plot the glyphs (i.e., select a geom)

Still Nothing! We need to tell it what our axis are.

Note that ggplot uses +, NOT %>%. This is because we are adding layers to our plots.

ggplot(data = Names) + 
  geom_line()
Error in `geom_line()`:
! Problem while setting up geom.
ℹ Error occurred in the 1st layer.
Caused by error in `compute_geom_1()`:
! `geom_line()` requires the following missing aesthetics: x and y
Backtrace:
  1. base (local) `<fn>`(x)
  2. ggplot2:::print.ggplot(x)
  4. ggplot2:::ggplot_build.ggplot(x)
  5. ggplot2:::by_layer(...)
 12. ggplot2 (local) f(l = layers[[i]], d = data[[i]])
 13. l$compute_geom_1(d)
 14. ggplot2 (local) compute_geom_1(..., self = self)

Note - this is why I like to map aesthetics first, so we can avoid errors.

  1. Map the aesthetics

Rule of thumb: anytime when you are plotting with ggplot, ALL variables need to be inside an aes (except facets, later in slides), and all constants go outside of the aes.

#not Quite
ggplot(data = Names) + 
  geom_line( aes(x = year, y = total)) 


#add groups
ggplot(data = Names) + 
  geom_line( aes(x = year, y = total, group = name)) 


#add color
ggplot(data = Names) + 
  geom_line( aes(x = year, y = total, color = name)) 

NA
NA
  1. Add labels and title
ggplot(data = Names) + 
  geom_line( aes(x = year, y = total, color = name)) +
  ggtitle("Names Over Time") +
  xlab("Year") +
  ylab("Popularity") +
  guides(color = guide_legend(title = "Siblings Names" ))

NA
NA
  1. other features (e.g., alpha, sizing, etc)
ggplot(data = Names) + 
  geom_line( aes(x = year, y = total, color = name, linetype = name)) +
  ggtitle("Names Over Time") +
  xlim(c(1972, 2022))+
  xlab("Year") +
  ylab("Popularity") +
  guides(color = guide_legend(title = "Siblings Names" ), 
         linetype = guide_legend(title = "Still Siblings Names" ))

NA
NA

Remarks about faceting: facet_wrap()

The syntax for facets requires a formula syntax we haven’t seen much yet. There are two main ways to plot with facets. Here are a few pointers:

Facet Wrap

  • facet_wrap() just makes a seperate plot for each level of the categorical variable
    • Syntax: facet_wrap( ~ categoricalVariable)
    • For example:

Facet Grid

Difference between color and fill

library(mosaicData)

head(CPS85)

CPS85 %>% 
  ggplot() +
  geom_density(aes(x = wage, color = sex), alpha = 0.4)+
  facet_grid( ~ married) +
  xlim(0,30) 

  
CPS85 %>% 
  ggplot() +
  geom_density(aes(x = wage, fill = sex), alpha = 0.4)+
  facet_grid( ~ married) +
  xlim(0,30) 


  
CPS85 %>% 
  ggplot() +
  geom_density(aes(x = wage, fill = sex, color = sex), alpha = 0.4)+
  facet_grid( ~ married) +
  xlim(0,30)




CPS85%>%
  ggplot(aes(x = married, color = sex)) + 
  geom_bar() +
  facet_wrap( ~ union, scales = "free")  #Note the scales here 


CPS85%>%
  ggplot(aes(x = married, fill = sex)) + 
  geom_bar()+
  facet_wrap( ~ union, scales = "free")  #Note the scales here 



CPS85%>%
  ggplot(aes(x = age, y = wage, color = sex)) + 
  geom_point()


CPS85%>%
  ggplot(aes(x = age, y = wage, fill = sex)) +  #fill does not work for points!
  geom_point()

NA
NA

Another Example using Diamonds Data

  1. establish the frame

  2. plot the glyphs (i.e., select a geom)

  3. map the aesthetics

  4. add labels and title

  5. other features (e.g., alpha, sizing, etc)

  6. Establish the Frame

ggplot(data = diamonds)

  1. plot the glyphs (i.e., select a geom)
ggplot(data = diamonds) +
  geom_point()
Error in `geom_point()`:
! Problem while setting up geom.
ℹ Error occurred in the 1st layer.
Caused by error in `compute_geom_1()`:
! `geom_point()` requires the following missing aesthetics: x and y
Backtrace:
  1. base (local) `<fn>`(x)
  2. ggplot2:::print.ggplot(x)
  4. ggplot2:::ggplot_build.ggplot(x)
  5. ggplot2:::by_layer(...)
 12. ggplot2 (local) f(l = layers[[i]], d = data[[i]])
 13. l$compute_geom_1(d)
 14. ggplot2 (local) compute_geom_1(..., self = self)

  1. Map the aesthetics
ggplot(data = diamonds, aes(x = carat, y = price)) +
  geom_point()

  1. Add Titles and Labels
ggplot(data = diamonds, aes(x = carat, y = price)) +
  geom_point(aes(color = depth), alpha = 0.5, size = 1) +
  ggtitle("Diamonds Data") +
  xlab("Carat") +
  ylab("Price")

  1. Add additional features

Notice that I can have aes inside multiple statements. Notice that when I use constants (like alpha = 0.3, size = 0.1) they ARE NOT inside aes.

In general, variables go inside aes and constants go outside of it. (unless we are using facets then see previous materials.)

ggplot(data = diamonds, aes(x = carat, y = price)) +
  geom_point(aes(colour = depth), alpha = 0.3, size = 0.1) +
  ggtitle("Diamonds Data") +
  xlab("Carat") +
  ylab("Price") +
  facet_grid( cut ~ color)


ggplot(data = diamonds, aes(x = carat, y = price)) +
  geom_point(colour = "red", alpha = 0.3, size = 0.1) +
  ggtitle("Diamonds Data") +
  xlab("Carat") +
  ylab("Price") +
  facet_grid( cut ~ color)

Side Note about placement of aes

aes can either go inside the ggplot() function, or inside the geom_[chart]() function itself, or both. The 3 following options create the same plots, but the code is slightly different.

#option 1
ggplot(data = diamonds, ) +
  geom_point(aes(x = carat, y = price, color = clarity),
             alpha = 0.2, 
             size = 1) +
  geom_smooth(method = "glm" , 
              formula = y ~ poly(x, 2),                     # y = b_0 + b_1 x + b_2 x^2 + e
              aes(x = carat, y = price), 
              color = "red") +
  ylim(c(0, 20000))

  


#option 2
ggplot(data = diamonds, aes(x = carat, y = price, color = clarity)) +
  geom_point(alpha = 0.2, 
             size = 1) +
  geom_smooth(method = "glm" , 
              formula = y ~ poly(x, 2),                     # y = b_0 + b_1 x + b_2 x^2 + e
              aes(x = carat, y = price), 
              color = "red") +
  ylim(c(0, 20000))

  

#Option 3
ggplot(data = diamonds,  aes(x = carat, y = price) )+ 
  geom_point( aes(color = clarity),
              alpha = 0.2, 
              size = 1) +
  geom_smooth(method = "glm" , 
              formula = y ~ poly(x, 2),                     # y = b_0 + b_1 x + b_2 x^2 + e
              color = "red") +
  ylim(c(0, 20000))

LS0tCnRpdGxlOiAiTDEwIC0gQmFjayB0byBgZ2dwbG90MmAiCnN1YnRpdGxlOiAiRGF0YSBDb21wdXRpbmcgQ2hhcHRlciA4IgphdXRob3I6IHwKICAgICAgICB8IFByZXNlbnRlcjogT2xpdmlhIEJlY2sKICAgICAgICB8IENvbnRlbnQgY3JlZGl0OiBNYXR0aGV3IEJlY2ttYW4Kb3V0cHV0OiAKICAgIHNsaWR5X3ByZXNlbnRhdGlvbjogZGVmYXVsdAogICAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkY0RhdGEpCmxpYnJhcnkobW9zYWljKQpsaWJyYXJ5KGVzcXVpc3NlKQprbml0cjo6b3B0c19jaHVuayRzZXQodGlkeT1GQUxTRSwgbWVzc2FnZT1GQUxTRSkKb3B0aW9ucyh3aWR0aCA9IDgwKQpgYGAKCgojIyBBZ2VuZGEKCi0gYnJpZWYgaW50cm9kdWN0aW9uIHRvIGA6OmAKLSBgZ2dwbG90KClgIGZseW92ZXIKLSByZW1hcmtzIGFib3V0IGZhY2V0cwotIGBjb2xvcmAgdnMuIGBmaWxsYAoKCiMjIyMgUmVtaW5kZXJzIAoKLSBNaWR0ZXJtIGlzIEp1bmUgOSRee3RofSQgaW4gY2xhc3MgCiAgLSBSZXZpZXcgaXMgcG9zdGVkIG9uIENhbnZhcwogIC0gTGV0IG1lIGtub3cgaWYgeW91IGhhdmUgYW55IHF1ZXN0aW9ucyBvciB3YW50IHNvbHV0aW9ucyB0byBwcmV2aW91cyBhc3NpZ25tZW50cyAKLSBGaW5hbCBQcm9qZWN0IElkZWFzICsgR3JvdXBzIGR1ZSAtLS0tLS0tLS0tCiAgLSBuZWVkIGEgInNvbGlkIiBpZGVhIG9mIHdoYXQgeW91IG1pZ2h0IGxvb2sgYXQgCiAgLSBuZWVkIGRhdGEgc2V0cywgb3IgaWRlYXMgZm9yIGRhdGEgc2V0cyAKICAgIC0gdGhlc2UgZG8gbm90IG5lZWQgdG8gYmUgeW91ciBmaW5hbCBkYXRhIHNldHMsIGJ1dCBJIGp1c3Qgd2FudCB0byBzZWUgeW91IGhhdmUgYmVlbiB0aGlua2luZyBhYm91dCB0aGlzIHByb2plY3QgCiAgLSBZb3UgY2FuIHdvcmsgYnkgeW91cnNlbGYgb3Igd2l0aCBhIHBhcnRuZXIgCiAgLSBGaWxsIG91dCB0aGUgY2FudmFzICJxdWl6IiB0byBsZXQgbWUga25vdyBpZiB5b3Ugd2FudCB0byB3b3JrIGJ5IHlvdXJzZWxmIG9yIHdpdGggc29tZW9uZSBlbHNlLiAKICAtIElmIHlvdSB3YW50IHRvIHdvcmsgd2l0aCBhIHBhcnRuZXIsIGJ1dCBkb24ndCBrbm93IHdobyB0byB3b3JrIHdpdGgsIGxldCBtZSBrbm93IGFuZCBJIHdpbGwgZmluZCBzb21lb25lCgojIyBQYWNrYWdlTmFtZTo6RnVuY3Rpb25OYW1lCgotIFdlIGNhbiB1c2UgdGhlIGA6OmAgZnVuY3Rpb24gdG8gcmVmZXJlbmNlIGZ1bmN0aW9ucyBpbnNpZGUgcGFja2FnZXMuIAogIC0gVGhpcyBoZWxwcyB1cyBiZSBleHRyYSBzdXJlIHRoYXQgd2UgYXJlIHVzaW5nIHRoZSBleGFjdCBmdW5jdGlvbiB3ZSB3YW50IHRvIGJlCiAgLSBIZWxwcyBhdm9pZCBjb25mbGljdCAoaS5lLiB3aGVuIDIgcGFja2FnZXMgdGhhdCBoYXZlIGEgZnVuY3Rpb24gd2l0aCB0aGUgc2FtZSBuYW1lIHRoYXQgZG8gZGlmZmVyZW50IHRoaW5ncykKICAgIC0gYHNlbGVjdGAgaXMgYSB2ZXJ5IGNvbW1vbiBmdW5jdGlvbiBuYW1lLiBVc3VhbGx5IHdlIG5lZWQgdG8gdXNlIGBkcGx5cjo6c2VsZWN0YAoKCgpgYGB7ciwgbWVzc2FnZT1UUlVFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKaGVhZChkaWFtb25kcykKCgojP2ZpbHRlcgoKI2ZpbHRlciBmcm9tIGRwbHlyCmRpYW1vbmRzICU+JQogIGRwbHlyOjpmaWx0ZXIoY29sb3IgPT0gIkUiKSAlPiUKICBoZWFkKCkKCiNub3JtYWwKZGlhbW9uZHMgJT4lCiAgZmlsdGVyKGNvbG9yID09ICJFIikgJT4lCiAgaGVhZCgpCgpgYGAKCgoKCiMjIEJ1aWxkaW5nIEdyYXBoaWNzCgoxLiBEcmF3IGJ5IGhhbmQgKG9yIGltYWdpbmUpIHRoZSBzcGVjaWZpYyBwbG90IHRoYXQgeW91IGludGVuZCB0byBjb25zdHJ1Y3QKMi4gRGF0YSBXcmFuZ2xpbmcgKGlmIG5lZWRlZCkgdG8gZ2V0IHRoZSBkYXRhIGluIGdseXBoLXJlYWR5IGZvcm0sIG9yIHZlcmlmeSB0aGF0IHRoZSBjdXJyZW50IGZvcm0gaXMgZ2x5cGgtcmVhZHkgZm9yIHlvdXIgcHVycG9zZXMuCjMuIEVzdGFibGlzaCB0aGUgZnJhbWUgdXNpbmcgYSBgZ2dwbG90KClgIHN0YXRlbWVudAo0LiBDcmVhdGUgdGhlIGludGVuZGVkIGdseXBoIHVzaW5nIGBnZW9tX1tzdHlsZV0oKWAgc3VjaCBhcwogICAgLSBgZ2VvbV9wb2ludCgpYAogICAgLSBgZ2VvbV9iYXIoKWAKICAgIC0gYGdlb21fYm94cGxvdCgpYAogICAgLSBgZ2VvbV9kZW5zaXR5KClgCiAgICAtIGBnZW9tX3ZsaW5lKClgCiAgICAtIGBnZW9tX3NlZ21lbnQoKWAKICAgIC0gYGdlb21faGlzdG9ncmFtKClgCiAgICAtIGFuZCAqbWFueSogbW9yZQo1LiBNYXAgdmFyaWFibGVzIHRvIHRoZSBncmFwaGljYWwgYXR0cmlidXRlcyBvZiB0aGUgZ2x5cGggdXNpbmc6IGBhZXMoIClgCiAgLSBSdWxlIG9mIHRodW1iOiBhbnl0aW1lIHdoZW4geW91IGFyZSBwbG90dGluZyB3aXRoIGdncGxvdCwgQUxMIHZhcmlhYmxlcyBuZWVkIHRvIGJlIGluc2lkZSBhbiBgYWVzYCAoZXhjZXB0IGZhY2V0cywgbGF0ZXIgaW4gc2xpZGVzKSwgYW5kIGFsbCBjb25zdGFudHMgZ28gb3V0c2lkZSBvZiB0aGUgYGFlc2AuCiAgICAtIGUuZy4gYGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZ2VuZGVyKSlgIHZzLiBgZ2VvbV9wb2ludChjb2xvciA9ICJyZWQiKWAKICAKNi4gQWRkIGFkZGl0aW9uYWwgbGF5ZXJzIHRvIHRoZSBmcmFtZSB1c2luZyB0aGUgYCtgIHN5bWJvbCAKICAgIC0gTm90ZTogKipub3QqKiBgJT4lYCBiZXR3ZWVuIGxheWVycyBvZiBgZ2dwbG90MmAgZ3JhcGhpY3MKICAgIC0gVGhpbmsgYCtgIGlzIGVxdWl2YWxlbnQgb2YgImFkZCBsYXllciBvbiB0b3Agb2YgLi4uIiBpbiBgZ2dwbG90MmAgcG9ydGlvbnMsIHdoZXJlYXMgYCU+JWAgaXMgICJhbmQgdGhlbiB0aGUgbmV4dCBzdGVwIGlzLi4uIgoKKlN0ZXBzIDQgYW5kIDUgY2FuIGJlIHN3aXRjaGVkLioKCiFbaHR0cHM6Ly90d2l0dGVyLmNvbS90YW55YV9zaGFwaXJvL3N0YXR1cy8xNTc2OTM1MTUyNTc1MzQwNTQ0P3Q9dndhVzhoNkNDNjJoMHBrd3Y5bjVZZyZzPTE5XShpbWFnZXMvZ2dwbG90LWNha2UuanBnKQoKCiMjIEV4YW1wbGU6IEJhYnkgTmFtZXMgCgpMZXQncyBsb29rIGF0IG91ciBgQmFieU5hbWVzYCBuYW1lcyBkYXRhIHNldCBhZ2lhbi4gCgpgYGB7cn0KIyBkYXRhIGludGFrZQpkYXRhKCJCYWJ5TmFtZXMiLCBwYWNrYWdlID0gImRjRGF0YSIpCgojIGluc3BlY3QgZGF0YSBpbnRha2UKZ2xpbXBzZShCYWJ5TmFtZXMpCgpgYGAKCgoKIyMgd3JhbmdsZSBpbnRvIGdseXBoLXJlYWR5IGZvcm0KCgpgYGB7cn0KbmFtZXMgPC0gYygiT2xpdmlhIiwgIlpvZSIsICJRdWVudGluIikKCk5hbWVzIDwtIAogIEJhYnlOYW1lcyAlPiUKICBmaWx0ZXIobmFtZSAlaW4lIG5hbWVzKSAlPiUKICBncm91cF9ieShuYW1lLCB5ZWFyKSAlPiUKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY291bnQsIG5hLnJtID0gVFJVRSkpCgpOYW1lcyAlPiUKICBoZWFkKCkKCmBgYAoKCiMjIGluIHRoZSBiZWdpbm5pbmcgeW91IG1pZ2h0IHVzZSBtcGxvdCB0byBnZXQgc3RhcnRlZC0taGVyZSdzIHRoZSBkZWZhdWx0IHJlc3VsdAoKVGhlIGdyYXBoIGxvb2tzIHBlcmZlY3RseSBmaW5lLCBidXQgdGhpcyBjb2RlIGlzbid0IGVhc3kgdG8gcmVhZC4KClRoaXMgaXMgd2h5IHdlIHN0cmVzcyB3cml0aW5nIHJlYWRhYmxlIGNvZGUhIAoKYGBge3J9CmdncGxvdChkYXRhID0gTmFtZXMsIGFlcyh4ID0geWVhciwgeSA9IHRvdGFsKSkgKyBnZW9tX2xpbmUoKSAgKyBhZXMoY29sb3VyID0gbmFtZSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArIGxhYnModGl0bGUgPSAiIikKYGBgCgoKIyMgd2UgY2FuIGRvIGJldHRlciAKMS4gZXN0YWJsaXNoIHRoZSBmcmFtZQoyLiBwbG90IHRoZSBnbHlwaHMgKGkuZS4sIHNlbGVjdCBhIGdlb20pCjMuIG1hcCB0aGUgYWVzdGhldGljcwo0LiBhZGQgbGFiZWxzIGFuZCB0aXRsZQo1LiBvdGhlciBmZWF0dXJlcyAoZS5nLiwgYWxwaGEsIHNpemluZywgZXRjKQoKCiMjIyMgT3VyIFBsb3QgCgoxLiBFc3RhYmxpc2ggdGhlIEZyYW1lCgpOb3RoaW5nIGlzIGhlcmUhIFRoYXQgaXMgZXhhY3RseSB3aGF0IGlzIHN1cHBvc2VkIHRvIGhhcHBlbi4gQ2FsbGluZyBgZ2dwbG90KClgIG9ubHkgdGVsbHMgdXMgUiB0aGF0IHdlIGFyZSByZWFkeSB0byBwbG90IGFuZCBJIHdhbnQgdG8gY3JlYXRlIHNvbWUgc3BhY2UgdG8gbWFrZSBteSBwbG90LiAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IE5hbWVzKSAKICAKYGBgCgoyLiBwbG90IHRoZSBnbHlwaHMgKGkuZS4sIHNlbGVjdCBhIGdlb20pCgpTdGlsbCBOb3RoaW5nISBXZSBuZWVkIHRvIHRlbGwgaXQgd2hhdCBvdXIgYXhpcyBhcmUuIAoKTm90ZSB0aGF0IGdncGxvdCB1c2VzIGArYCwgTk9UIGAlPiVgLiBUaGlzIGlzIGJlY2F1c2Ugd2UgYXJlICoqYWRkaW5nKiogbGF5ZXJzIHRvIG91ciBwbG90cy4KCmBgYHtyLCBlcnJvcj1UfQpnZ3Bsb3QoZGF0YSA9IE5hbWVzKSArIAogIGdlb21fbGluZSgpCgpgYGAKCgpOb3RlIC0gdGhpcyBpcyB3aHkgSSBsaWtlIHRvIG1hcCBhZXN0aGV0aWNzIGZpcnN0LCBzbyB3ZSBjYW4gYXZvaWQgZXJyb3JzLiAKCgozLiBNYXAgdGhlIGFlc3RoZXRpY3MKClJ1bGUgb2YgdGh1bWI6IGFueXRpbWUgd2hlbiB5b3UgYXJlIHBsb3R0aW5nIHdpdGggZ2dwbG90LCBBTEwgdmFyaWFibGVzIG5lZWQgdG8gYmUgaW5zaWRlIGFuIGBhZXNgIChleGNlcHQgZmFjZXRzLCBsYXRlciBpbiBzbGlkZXMpLCBhbmQgYWxsIGNvbnN0YW50cyBnbyBvdXRzaWRlIG9mIHRoZSBgYWVzYC4gCgoKYGBge3J9CiNub3QgUXVpdGUKZ2dwbG90KGRhdGEgPSBOYW1lcykgKyAKICBnZW9tX2xpbmUoIGFlcyh4ID0geWVhciwgeSA9IHRvdGFsKSkgCgojYWRkIGdyb3VwcwpnZ3Bsb3QoZGF0YSA9IE5hbWVzKSArIAogIGdlb21fbGluZSggYWVzKHggPSB5ZWFyLCB5ID0gdG90YWwsIGdyb3VwID0gbmFtZSkpIAoKI2FkZCBjb2xvcgojIG5vdGUgdGhhdCBjb2xvciBpbmNsdWRlcyB0aGUgZ3JvdXBzIGFyZ3VtZW50IGJ1dCBub3QgdmljZSB2ZXJzYSEgCmdncGxvdChkYXRhID0gTmFtZXMpICsgCiAgZ2VvbV9saW5lKCBhZXMoeCA9IHllYXIsIHkgPSB0b3RhbCwgY29sb3IgPSBuYW1lKSkgCgoKYGBgCgoKNC4gQWRkIGxhYmVscyBhbmQgdGl0bGUKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBOYW1lcykgKyAKICBnZW9tX2xpbmUoIGFlcyh4ID0geWVhciwgeSA9IHRvdGFsLCBjb2xvciA9IG5hbWUpKSArCiAgZ2d0aXRsZSgiTmFtZXMgT3ZlciBUaW1lIikgKwogIHhsYWIoIlllYXIiKSArCiAgeWxhYigiUG9wdWxhcml0eSIpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiU2libGluZ3MgTmFtZXMiICkpCgoKYGBgCgoKCjUuIG90aGVyIGZlYXR1cmVzIChlLmcuLCBhbHBoYSwgc2l6aW5nLCBldGMpCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBOYW1lcykgKyAKICBnZW9tX2xpbmUoIGFlcyh4ID0geWVhciwgeSA9IHRvdGFsLCBjb2xvciA9IG5hbWUsIGxpbmV0eXBlID0gbmFtZSkpICsKICBnZ3RpdGxlKCJOYW1lcyBPdmVyIFRpbWUiKSArCiAgeGxpbShjKDE5NzIsIDIwMjIpKSsKICB4bGFiKCJZZWFyIikgKwogIHlsYWIoIlBvcHVsYXJpdHkiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIlNpYmxpbmdzIE5hbWVzIiApLCAKICAgICAgICAgbGluZXR5cGUgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiU3RpbGwgU2libGluZ3MgTmFtZXMiICkpCgoKYGBgCgoKCgoKCiMjIFJlbWFya3MgYWJvdXQgZmFjZXRpbmc6IGBmYWNldF93cmFwKClgCgpUaGUgc3ludGF4IGZvciBmYWNldHMgcmVxdWlyZXMgYSBmb3JtdWxhIHN5bnRheCB3ZSBoYXZlbid0IHNlZW4gbXVjaCB5ZXQuICBUaGVyZSBhcmUgdHdvIG1haW4gd2F5cyB0byBwbG90IHdpdGggZmFjZXRzLiAgSGVyZSBhcmUgYSBmZXcgcG9pbnRlcnM6CgojIyMgRmFjZXQgV3JhcAoKLSBgZmFjZXRfd3JhcCgpYCBqdXN0IG1ha2VzIGEgc2VwZXJhdGUgcGxvdCBmb3IgZWFjaCBsZXZlbCBvZiB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGUKICAgIC0gU3ludGF4OiBgZmFjZXRfd3JhcCggfiBjYXRlZ29yaWNhbFZhcmlhYmxlKWAKICAgIC0gRm9yIGV4YW1wbGU6CgpgYGB7cn0KZGF0YSgiTkNIUyIpCgojIGAhaXMubmEoc21va2VyKWAgZmluZHMgY2FzZXMgdGhhdCBhcmUgbm9uLW1pc3NpbmcgZm9yIGBzbW9rZXJgIChpLmUuIHJlbW92ZXMgTkEncykKSGVpZ2h0cyA8LSAKICBOQ0hTICU+JQogIGZpbHRlcihhZ2UgPiAyMCwgIWlzLm5hKHNtb2tlcikpICU+JSAgIAogIGdyb3VwX2J5KHNleCwgc21va2VyLCBhZ2UpICU+JQogIHN1bW1hcmlzZShoZWlnaHQgPSBtZWFuKGhlaWdodCwgbmEucm0gPSBUUlVFKSkKCmhlYWQoSGVpZ2h0cykKCkhlaWdodHMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYWdlLCB5ID0gaGVpZ2h0KSkgKyAgIAogIGdlb21fbGluZShhZXMobGluZXR5cGUgPSBzbW9rZXIpKSArICAgCiAgZmFjZXRfd3JhcCggfiBzZXgpCmBgYAoKIyMgRmFjZXQgR3JpZAoKLSBgZmFjZXRfZ3JpZCgpYCBhbGxvd3MgY29udHJvbCBvZiByb3cgJiBjb2x1bW4gZmFjZXRzCi0gYGZhY2V0X2dyaWQoKWAgc3ludGF4OgogICAgLSByb3cgJiBjb2x1bW4gZmFjZXRzOiBgZmFjZXRfZ3JpZChyb3dzIH4gY29scylgCiAgICAtIHJvdyBmYWNldHMgb25seTogYGZhY2V0X2dyaWQoIHJvd3MgfiAuIClgIChub3RlIHRoZSByZXF1aXJlZCAiYC5gIikgCiAgICAtIGNvbHVtbiBmYWNldHMgb25seTogYGZhY2V0X2dyaWQoIH4gY29scylgIChubyAiYC5gIiB0aGlzIHRpbWUpCgpgYGB7cn0KSGVpZ2h0cyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhZ2UsIHkgPSBoZWlnaHQpKSArIAogIGdlb21fbGluZShhZXMobGluZXR5cGUgPSBzbW9rZXIpKSArIAogIGZhY2V0X2dyaWQoc2V4IH4gLikKYGBgCgpgYGB7cn0KSGVpZ2h0cyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhZ2UsIHkgPSBoZWlnaHQpKSArIAogIGdlb21fbGluZSgpICsgCiAgZmFjZXRfZ3JpZChzZXggfiBzbW9rZXIpCmBgYAoKCiMjIERpZmZlcmVuY2UgYmV0d2VlbiBgY29sb3JgIGFuZCBgZmlsbGAKCmBgYHtyfQpsaWJyYXJ5KG1vc2FpY0RhdGEpCgpoZWFkKENQUzg1KQoKQ1BTODUgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2RlbnNpdHkoYWVzKHggPSB3YWdlLCBjb2xvciA9IHNleCksIGFscGhhID0gMC40KSsKICBmYWNldF9ncmlkKCB+IG1hcnJpZWQpICsKICB4bGltKDAsMzApIAogIApDUFM4NSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fZGVuc2l0eShhZXMoeCA9IHdhZ2UsIGZpbGwgPSBzZXgpLCBhbHBoYSA9IDAuNCkrCiAgZmFjZXRfZ3JpZCggfiBtYXJyaWVkKSArCiAgeGxpbSgwLDMwKSAKCiAgCkNQUzg1ICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gd2FnZSwgZmlsbCA9IHNleCwgY29sb3IgPSBzZXgpLCBhbHBoYSA9IDAuNCkrCiAgZmFjZXRfZ3JpZCggfiBtYXJyaWVkKSArCiAgeGxpbSgwLDMwKQoKCgpDUFM4NSU+JQogIGdncGxvdChhZXMoeCA9IG1hcnJpZWQsIGNvbG9yID0gc2V4KSkgKyAKICBnZW9tX2JhcigpICsKICBmYWNldF93cmFwKCB+IHVuaW9uLCBzY2FsZXMgPSAiZnJlZSIpICAjTm90ZSB0aGUgc2NhbGVzIGhlcmUgCgpDUFM4NSU+JQogIGdncGxvdChhZXMoeCA9IG1hcnJpZWQsIGZpbGwgPSBzZXgpKSArIAogIGdlb21fYmFyKCkrCiAgZmFjZXRfd3JhcCggfiB1bmlvbiwgc2NhbGVzID0gImZyZWUiKSAgI05vdGUgdGhlIHNjYWxlcyBoZXJlIAoKCkNQUzg1JT4lCiAgZ2dwbG90KGFlcyh4ID0gYWdlLCB5ID0gd2FnZSwgY29sb3IgPSBzZXgpKSArIAogIGdlb21fcG9pbnQoKQoKQ1BTODUlPiUKICBnZ3Bsb3QoYWVzKHggPSBhZ2UsIHkgPSB3YWdlLCBmaWxsID0gc2V4KSkgKyAgI2ZpbGwgZG9lcyBub3Qgd29yayBmb3IgcG9pbnRzIQogIGdlb21fcG9pbnQoKQoKCmBgYAoKCgoKCgoKCgojIyBBbm90aGVyIEV4YW1wbGUgdXNpbmcgRGlhbW9uZHMgRGF0YQoKMS4gZXN0YWJsaXNoIHRoZSBmcmFtZQoyLiBwbG90IHRoZSBnbHlwaHMgKGkuZS4sIHNlbGVjdCBhIGdlb20pCjMuIG1hcCB0aGUgYWVzdGhldGljcwo0LiBhZGQgbGFiZWxzIGFuZCB0aXRsZQo1LiBvdGhlciBmZWF0dXJlcyAoZS5nLiwgYWxwaGEsIHNpemluZywgZXRjKQoKMS4gRXN0YWJsaXNoIHRoZSBGcmFtZQoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpCmBgYAoKMi4gcGxvdCB0aGUgZ2x5cGhzIChpLmUuLCBzZWxlY3QgYSBnZW9tKQoKYGBge3IsIGVycm9yID0gVFJVRX0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fcG9pbnQoKQoKYGBgCgozLiBNYXAgdGhlIGFlc3RoZXRpY3MKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKSArCiAgZ2VvbV9wb2ludCgpCgpgYGAKCgo0LiBBZGQgVGl0bGVzIGFuZCBMYWJlbHMgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZGVwdGgpLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDEpICsKICBnZ3RpdGxlKCJEaWFtb25kcyBEYXRhIikgKwogIHhsYWIoIkNhcmF0IikgKwogIHlsYWIoIlByaWNlIikKCmBgYAoKCjUuIEFkZCBhZGRpdGlvbmFsIGZlYXR1cmVzIAoKCk5vdGljZSB0aGF0IEkgY2FuIGhhdmUgYGFlc2AgaW5zaWRlIG11bHRpcGxlIHN0YXRlbWVudHMuIE5vdGljZSB0aGF0IHdoZW4gSSB1c2UgY29uc3RhbnRzIChsaWtlIGBhbHBoYSA9IDAuMywgc2l6ZSA9IDAuMWApIHRoZXkgQVJFIE5PVCBpbnNpZGUgYGFlc2AuIAoKSW4gZ2VuZXJhbCwgdmFyaWFibGVzIGdvIGluc2lkZSBgYWVzYCBhbmQgY29uc3RhbnRzIGdvIG91dHNpZGUgb2YgaXQuICh1bmxlc3Mgd2UgYXJlIHVzaW5nIGZhY2V0cyB0aGVuIHNlZSBwcmV2aW91cyBtYXRlcmlhbHMuKQoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBkZXB0aCksIGFscGhhID0gMC4zLCBzaXplID0gMC4xKSArCiAgZ2d0aXRsZSgiRGlhbW9uZHMgRGF0YSIpICsKICB4bGFiKCJDYXJhdCIpICsKICB5bGFiKCJQcmljZSIpICsKICBmYWNldF9ncmlkKCBjdXQgfiBjb2xvcikKCmdncGxvdChkYXRhID0gZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICJyZWQiLCBhbHBoYSA9IDAuMywgc2l6ZSA9IDAuMSkgKwogIGdndGl0bGUoIkRpYW1vbmRzIERhdGEiKSArCiAgeGxhYigiQ2FyYXQiKSArCiAgeWxhYigiUHJpY2UiKSArCiAgZmFjZXRfZ3JpZCggY3V0IH4gY29sb3IpCgpgYGAKCgoKCgoKIyMgU2lkZSBOb3RlIGFib3V0IHBsYWNlbWVudCBvZiBgYWVzYAoKYGFlc2AgY2FuIGVpdGhlciBnbyBpbnNpZGUgdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24sIG9yIGluc2lkZSB0aGUgYGdlb21fW2NoYXJ0XSgpYCBmdW5jdGlvbiBpdHNlbGYsIG9yIGJvdGguIFRoZSAzIGZvbGxvd2luZyBvcHRpb25zIGNyZWF0ZSB0aGUgc2FtZSBwbG90cywgYnV0IHRoZSBjb2RlIGlzIHNsaWdodGx5IGRpZmZlcmVudC4gCgpgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlID0gRn0KI29wdGlvbiAxCmdncGxvdChkYXRhID0gZGlhbW9uZHMsICkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlLCBjb2xvciA9IGNsYXJpdHkpLAogICAgICAgICAgICAgYWxwaGEgPSAwLjIsIAogICAgICAgICAgICAgc2l6ZSA9IDEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAiZ2xtIiAsIAogICAgICAgICAgICAgIGZvcm11bGEgPSB5IH4gcG9seSh4LCAyKSwgICAgICAgICAgICAgICAgICAgICAjIHkgPSBiXzAgKyBiXzEgeCArIGJfMiB4XjIgKyBlCiAgICAgICAgICAgICAgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSwgCiAgICAgICAgICAgICAgY29sb3IgPSAicmVkIikgKwogIHlsaW0oYygwLCAyMDAwMCkpCiAgCgoKI29wdGlvbiAyCmdncGxvdChkYXRhID0gZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSwgY29sb3IgPSBjbGFyaXR5KSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjIsIAogICAgICAgICAgICAgc2l6ZSA9IDEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAiZ2xtIiAsIAogICAgICAgICAgICAgIGZvcm11bGEgPSB5IH4gcG9seSh4LCAyKSwgICAgICAgICAgICAgICAgICAgICAjIHkgPSBiXzAgKyBiXzEgeCArIGJfMiB4XjIgKyBlCiAgICAgICAgICAgICAgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSwgCiAgICAgICAgICAgICAgY29sb3IgPSAicmVkIikgKwogIHlsaW0oYygwLCAyMDAwMCkpCiAgCgojT3B0aW9uIDMKZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkgKSsgCiAgZ2VvbV9wb2ludCggYWVzKGNvbG9yID0gY2xhcml0eSksCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjIsIAogICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImdsbSIgLCAKICAgICAgICAgICAgICBmb3JtdWxhID0geSB+IHBvbHkoeCwgMiksICAgICAgICAgICAgICAgICAgICAgIyB5ID0gYl8wICsgYl8xIHggKyBiXzIgeF4yICsgZQogICAgICAgICAgICAgIGNvbG9yID0gInJlZCIpICsKICB5bGltKGMoMCwgMjAwMDApKQoKYGBgCgoKLSBJIHBlcnNvbmFsbHkgcHJlZmVyIHRvIHB1dCAiZ2xvYmFsIiBhZXN0aGV0aWNzIGluIHRoZSBgZ2dwbG90KClgIGFuZCAibG9jYWwiIGFlc3RoZXRpY3MgaW4gdGhlIGBnZW9tYC4gCiAgLSBPcHRpb24gMSA6IGFsbCBhZXN0aGV0aWNzIGFyZSBsb2NhbCB0byB0aGUgZ2VvbQogICAgIC0gTm90ZSB3ZSBoYXZlIHRvIHJlcGVhdCBgeGAgYW5kIGB5YAogIC0gT3B0aW9uIDIgOiBhbGwgYWVzdGhldGljcyBhcmUgZ2xvYmFsIHRvIHRoZSBnZ3Bsb3QKICAgIC0gTm90ZSB0aGF0IGBjb2xvciA9IGNsYXJpdHlgIGlzIG5vdCBuZWVkZWQgZm9yIGBnZW9tX3Ntb290aGAKICAtIE9wdGlvbiAzIDogZ2xvYmFsIGFlc3RoZXRpY3MgYXJlIGluIHRoZSBnZ3Bsb3QgYW5kIGxvY2FsIGFlc3RoZXRpY3MgYW5kIGluIHRoZSBnZW9tCiAgICAtIEJvdGggYGdlb21fcG9pbnRgIGFuZCBgZ2VvbV9zbW9vdGhgIHVzZSBgeGAgYW5kIGB5YCBzbyBJIHB1dCB0aGVtIGluIHRoZSBgZ2dwbG90KClgCiAgICAtIE9ubHkgYGdlb21fcG9pbnRgIHVzZXMgYGNvbG9yID0gY2xhcml0eWAgc28gSSBwdXQgdGhhdCBPTkxZIGluIHRoZSBgZ2VvbV9wb2ludGAgZnVuY3Rpb24KICAgIAotIEluIG15IG9waW5pb24sIE9wdGlvbiAzIGlzIHRoZSAiY2xlYW5lc3QiIGNvZGUuIFRoaXMgaXMgcGFydGx5IGJhc2VkIG9uIHN0eWxpc3RpYyBwcmVmZXJlbmNlIGFuZCBwYXJ0bHkgYmFzZWQgb24gc29tZSBpbnRlcm5hbCBtZWNoYW5pYyBvZiBnZ3Bsb3QncyAodGhhdCBpcyBiZXlvbmQgdGhlIHNjb3BlIG9mIHRoaXMgY291cnNlKS4gSG93IHlvdSB3cml0ZSB5b3VyIGNvZGUgaXMgdXAgdG8geW91LiBKdXN0IGtlZXAgaXQgcmVhZGFibGUhCgotIEJ1dCBhZ2FpbiwgYWxsIDMgY29kZXMgZ2VuZXJhdGUgdGhlIHRoZSBleGFjdCBzYW1lIHBsb3QgKHNvIGRvZXMgaXQgcmVhbGx5IG1hdHRlciB0aGF0IG11Y2ggd2hpY2ggb3B0aW9uIHdlIHVzZT8/KQoK